`define ALUSLL 4'd7
`define ALUSLL16 4'd6
`define ALUXOR 4'd5
`define ALUOR 4'd4
`define ALUAND 4'd3
`define ALUSUB 4'd2
`define ALUADD 4'd1
`define ALUnone 4'd0
`define load_ALUresult 3'b000
`define load_mem 3'b001
`define load_byte 3'b010
`define branch_none 3'b000
`define branch_BEQ 3'b001
`define branch_BGEZ 3'b010
`define none 6'd0
`define ORI 6'd1
`define LW 6'd2
`define SW 6'd3
`define BEQ 6'd4
`define LUI 6'd5
`define J 6'd6
`define JAL 6'd7
`define ADDIU 6'd8
`define BGEZ 6'd9
`define LB 6'd10
`define ADD 6'd11
`define SUB 6'd12
`define AND 6'd13
`define OR 6'd14
`define XOR 6'd15
`define SLL 6'd16
`define JR 6'd17
`define JALR 6'd18
`define R 6'd19
module Control(
        input [5:0] opcode,
        input [5:0] func,
        output RegDst,
        output RegWrite,
        output ALUSrc_sign,
        output ALUSrc_zero,
        output MemWrite,
        output MemRead,
        output [2:0] load_select,
        output [2:0] branch,
        output jump,
        output [3:0] ALU_operation,
        output jr,
        output write31
    );
    reg [5:0] f;
    reg [5:0] RF;
    always @(*) begin
        case(opcode)
            6'b000000:
                f=`R;
            6'b001101:
                f=`ORI;
            6'b100011:
                f=`LW;
            6'b101011:
                f=`SW;
            6'b000100:
                f=`BEQ;
            6'b001111:
                f=`LUI;
            6'b000010:
                f=`J;
            6'b000011:
                f=`JAL;
            6'b001001:
                f=`ADDIU;
            6'b000001:
                f=`BGEZ;
            6'b100000:
                f=`LB;
            default :
                f=`none;
        endcase
    end
    always @(*) begin
        if(f==`R) begin
            case(func)
                6'b100000:
                    RF=`ADD;
                6'b100010:
                    RF=`SUB;
                6'b100100:
                    RF=`AND;
                6'b100101:
                    RF=`OR;
                6'b100110:
                    RF=`XOR;
                6'b000000:
                    RF=`SLL;
                6'b001000:
                    RF=`JR;
                6'b001001:
                    RF=`JALR;
                default:
                    RF=`none;
            endcase
        end
        else
            RF=`none;
    end
    assign RegDst=(f==`R)?1'b1:1'b0;
    assign RegWrite=((f==`LB)||(f==`JAL)||(f==`R)||(f==`ORI)||(f==`LW)||(f==`LUI)||(f==`ADDIU)||(f==`JALR))?1'b1:1'b0;
    assign ALUSrc_sign=((f==`LB)||(f==`LW)||(f==`SW)||(f==`LUI)||(f==`ADDIU))?1'b1:1'b0;
    assign ALUSrc_zero=(f==`ORI)?1'b1:1'b0;
    assign MemWrite=(f==`SW)?1'b1:1'b0;
    assign MemRead=((f==`LW)||(f==`LB))?1'b1:1'b0;
    assign load_select=(f==`LB)?`load_byte:
           (f==`LW)?`load_mem:
           `load_ALUresult;
    assign branch=(f==`BGEZ)?`branch_BGEZ:
           (f==`BEQ)?`branch_BEQ:
           `branch_none;
    assign jump=((f==`J)||(RF==`JR)||(f==`JAL)||(RF==`JALR))?1'b1:1'b0;
    assign jr=((RF==`JR)||(RF==`JALR))?1'b1:1'b0;
    assign write31=((f==`JALR)||(f==`JAL))?1'b1:1'b0;
    assign ALU_operation=(RF==`SLL)?`ALUSLL:
           (f==`LUI)?`ALUSLL16:
           (RF==`XOR)?`ALUXOR:
           ((RF==`OR)||(f==`ORI))?`ALUOR:
           (RF==`AND)?`ALUAND:
           (RF==`SUB)?`ALUSUB:
           ((f==`SW)||(f==`ADDIU)||(f==`LB)||(f==`LW)||(RF==`ADD))?`ALUADD:
           `ALUnone;
endmodule



